1 using System;
2 using
System.Collections.Generic;
3
4 namespace
ProceduralToolkit
5 {

6     ///
<summary>
7     ///
Array extensions
8     ///
</summary>
9     
public static class ArrayE
10     {

11         ///
<summary>
12         ///
Gets the next or the first node in the <see cref="LinkedList{T}"/>
13         ///
</summary>
14         
public static LinkedListNode<T> NextOrFirst<T>(this LinkedListNode<T> current)
15         {
16             
return current.Next ?? current.List.First;
17         }

18
19         ///
<summary>
20         ///
Gets the previous or the last node in the <see cref="LinkedList{T}"/>
21         ///
</summary>
22         
public static LinkedListNode<T> PreviousOrLast<T>(this LinkedListNode<T> current)
23         {
24             
return current.Previous ?? current.List.Last;
25         }

26
27         ///
<summary>
28         ///
Looped indexer getter, allows out of bounds indices
29         ///
</summary>
30         
public static T GetLooped<T>(this T[] array, int index)
31         {
32             
if (index < 0)
33             {
34                 index = index%array.Length + array.Length;
35             }
36             
else if (index >= array.Length)
37             {
38                 index %= array.Length;
39             }
40             
return array[index];
41         }

42
43         ///
<summary>
44         ///
Looped indexer setter, allows out of bounds indices
45         ///
</summary>
46         
public static void SetLooped<T>(this T[] array, int index, T value)
47         {
48             
if (index < 0)
49             {
50                 index = index%array.Length + array.Length;
51             }
52             
else if (index >= array.Length)
53             {
54                 index %= array.Length;
55             }
56             array[index] =
value;
57         }

58
59         ///
<summary>
60         ///
Looped indexer getter, allows out of bounds indices
61         ///
</summary>
62         
public static T GetLooped<T>(this List<T> array, int index)
63         {
64             
if (index < 0)
65             {
66                 index = index%array.Count + array.Count;
67             }
68             
else if (index >= array.Count)
69             {
70                 index %= array.Count;
71             }
72             
return array[index];
73         }

74
75         ///
<summary>
76         ///
Looped indexer setter, allows out of bounds indices
77         ///
</summary>
78         
public static void SetLooped<T>(this List<T> array, int index, T value)
79         {
80             
if (index < 0)
81             {
82                 index = index%array.Count + array.Count;
83             }
84             
else if (index >= array.Count)
85             {
86                 index %= array.Count;
87             }
88             array[index] =
value;
89         }

90
91         ///
<summary>
92         ///
Checks if <paramref name="vector"/> is within array bounds
93         ///
</summary>
94         
public static bool IsInBounds<T>(this T[,] array, Vector2Int vector)
95         {
96             
return IsInBounds(array, vector.x, vector.y);
97         }

98
99         ///
<summary>
100         ///
Checks if <paramref name="x"/> and <paramref name="y"/> are within array bounds
101         ///
</summary>
102         
public static bool IsInBounds<T>(this T[,] array, int x, int y)
103         {
104             
if (array == null)
105             {
106                 
throw new ArgumentNullException("array");
107             }
108             
return x >= 0 && x < array.GetLength(0) && y >= 0 && y < array.GetLength(1);
109         }

110
111         ///
<summary>
112         ///
Visits all connected elements with the same value as start element
113         ///
</summary>
114         ///
<remarks>
115         ///
https://en.wikipedia.org/wiki/Flood_fill
116         ///
</remarks>
117         
public static void FloodVisit<T>(this T[,] array, Vector2Int start, Action<int, int> visit)
118         {
119             FloodVisit(array, start.x, start.y, visit);
120         }

121
122         ///
<summary>
123         ///
Visits all connected elements with the same value as start element
124         ///
</summary>
125         ///
<remarks>
126         ///
https://en.wikipedia.org/wiki/Flood_fill
127         ///
</remarks>
128         
public static void FloodVisit<T>(this T[,] array, int startX, int startY, Action<int, int> visit)
129         {
130             
if (array == null)
131             {
132                 
throw new ArgumentNullException("array");
133             }
134             
if (visit == null)
135             {
136                 
throw new ArgumentNullException("visit");
137             }
138             
if (startX < 0 || startX >= array.GetLength(0))
139             {
140                 
throw new ArgumentOutOfRangeException("startX");
141             }
142             
if (startY < 0 || startY >= array.GetLength(1))
143             {
144                 
throw new ArgumentOutOfRangeException("startY");
145             }
146
147             
bool[,] processed = new bool[array.GetLength(0), array.GetLength(1)];
148             T
value = array[startX, startY];
149
150             
var queue = new Queue<Vector2Int>();
151             queue.Enqueue(
new Vector2Int(startX, startY));
152             processed[startX, startY] =
true;
153
154             
while (queue.Count > 0)
155             {
156                 Vector2Int cell = queue.Dequeue();
157
158                 array.VisitVonNeumannNeighbours(cell.x, cell.y,
true, (x, y) =>
159                 {
160                     
if (array[x, y].Equals(value) && !processed[x, y])
161                     {
162                         queue.Enqueue(
new Vector2Int(x, y));
163                         processed[x, y] =
true;
164                     }
165                 });
166
167                 visit(cell.x, cell.y);
168             }
169         }

170
171         ///
<summary>
172         ///
Visits all connected elements with the same value as start element
173         ///
</summary>
174         ///
<remarks>
175         ///
https://en.wikipedia.org/wiki/Flood_fill
176         ///
</remarks>
177         
public static void FloodVisit<T>(this T[,] array, Vector2Int start, Action<int, int, bool> visit)
178         {
179             FloodVisit(array, start.x, start.y, visit);
180         }

181
182         ///
<summary>
183         ///
Visits all connected elements with the same value as start element
184         ///
</summary>
185         ///
<remarks>
186         ///
https://en.wikipedia.org/wiki/Flood_fill
187         ///
</remarks>
188         
public static void FloodVisit<T>(this T[,] array, int startX, int startY, Action<int, int, bool> visit)
189         {
190             
if (array == null)
191             {
192                 
throw new ArgumentNullException("array");
193             }
194             
if (visit == null)
195             {
196                 
throw new ArgumentNullException("visit");
197             }
198             
if (startX < 0 || startX >= array.GetLength(0))
199             {
200                 
throw new ArgumentOutOfRangeException("startX");
201             }
202             
if (startY < 0 || startY >= array.GetLength(1))
203             {
204                 
throw new ArgumentOutOfRangeException("startY");
205             }
206
207             
bool[,] processed = new bool[array.GetLength(0), array.GetLength(1)];
208             T
value = array[startX, startY];
209
210             
var queue = new Queue<Vector2Int>();
211             queue.Enqueue(
new Vector2Int(startX, startY));
212             processed[startX, startY] =
true;
213
214             
while (queue.Count > 0)
215             {
216                 Vector2Int cell = queue.Dequeue();
217
218                 
bool isBorderCell = false;
219                 array.VisitMooreNeighbours(cell.x, cell.y,
false, (x, y) =>
220                 {
221                     
if (array.IsInBounds(x, y))
222                     {
223                         
if (array[x, y].Equals(value))
224                         {
225                             
bool vonNeumannNeighbour = (x == cell.x || y == cell.y);
226                             
if (vonNeumannNeighbour && !processed[x, y])
227                             {
228                                 queue.Enqueue(
new Vector2Int(x, y));
229                                 processed[x, y] =
true;
230                             }
231                         }
232                         
else
233                         {
234                             isBorderCell =
true;
235                         }
236                     }
237                     
else
238                     {
239                         isBorderCell =
true;
240                     }
241                 });
242
243                 visit(cell.x, cell.y, isBorderCell);
244             }
245         }

246
247         ///
<summary>
248         ///
Visits four cells orthogonally surrounding a central cell
249         ///
</summary>
250         ///
<remarks>
251         ///
https://en.wikipedia.org/wiki/Von_Neumann_neighborhood
252         ///
</remarks>
253         
public static void VisitVonNeumannNeighbours<T>(this T[,] array, Vector2Int center, bool checkArrayBounds,
254             Action<
int, int> visit)
255         {
256             VisitVonNeumannNeighbours(array, center.x, center.y, checkArrayBounds, visit);
257         }

258
259         ///
<summary>
260         ///
Visits four cells orthogonally surrounding a central cell
261         ///
</summary>
262         ///
<remarks>
263         ///
https://en.wikipedia.org/wiki/Von_Neumann_neighborhood
264         ///
</remarks>
265         
public static void VisitVonNeumannNeighbours<T>(this T[,] array, int x, int y, bool checkArrayBounds,
266             Action<
int, int> visit)
267         {
268             
if (array == null)
269             {
270                 
throw new ArgumentNullException("array");
271             }
272             
if (visit == null)
273             {
274                 
throw new ArgumentNullException("visit");
275             }
276
277             
if (checkArrayBounds)
278             {
279                 
if (x > 0)
280                 {
281                     visit(x -
1, y);
282                 }
283                 
if (x + 1 < array.GetLength(0))
284                 {
285                     visit(x +
1, y);
286                 }
287                 
if (y > 0)
288                 {
289                     visit(x, y -
1);
290                 }
291                 
if (y + 1 < array.GetLength(1))
292                 {
293                     visit(x, y +
1);
294                 }
295             }
296             
else
297             {
298                 visit(x -
1, y);
299                 visit(x +
1, y);
300                 visit(x, y -
1);
301                 visit(x, y +
1);
302             }
303         }

304
305         ///
<summary>
306         ///
Visits eight cells surrounding a central cell
307         ///
</summary>
308         ///
<remarks>
309         ///
https://en.wikipedia.org/wiki/Moore_neighborhood
310         ///
</remarks>
311         
public static void VisitMooreNeighbours<T>(this T[,] array, Vector2Int center, bool checkArrayBounds,
312             Action<
int, int> visit)
313         {
314             VisitMooreNeighbours(array, center.x, center.y, checkArrayBounds, visit);
315         }

316
317         ///
<summary>
318         ///
Visits eight cells surrounding a central cell
319         ///
</summary>
320         ///
<remarks>
321         ///
https://en.wikipedia.org/wiki/Moore_neighborhood
322         ///
</remarks>
323         
public static void VisitMooreNeighbours<T>(this T[,] array, int x, int y, bool checkArrayBounds,
324             Action<
int, int> visit)
325         {
326             
if (array == null)
327             {
328                 
throw new ArgumentNullException("array");
329             }
330             
if (visit == null)
331             {
332                 
throw new ArgumentNullException("visit");
333             }
334
335             
if (checkArrayBounds)
336             {
337                 
bool xGreaterThanZero = x > 0;
338                 
bool xLessThanWidth = x + 1 < array.GetLength(0);
339
340                 
bool yGreaterThanZero = y > 0;
341                 
bool yLessThanHeight = y + 1 < array.GetLength(1);
342
343                 
if (yGreaterThanZero)
344                 {
345                     
if (xGreaterThanZero) visit(x - 1, y - 1);
346
347                     visit(x, y -
1);
348
349                     
if (xLessThanWidth) visit(x + 1, y - 1);
350                 }
351
352                 
if (xGreaterThanZero) visit(x - 1, y);
353                 
if (xLessThanWidth) visit(x + 1, y);
354
355                 
if (yLessThanHeight)
356                 {
357                     
if (xGreaterThanZero) visit(x - 1, y + 1);
358
359                     visit(x, y +
1);
360
361                     
if (xLessThanWidth) visit(x + 1, y + 1);
362                 }
363             }
364             
else
365             {
366                 visit(x -
1, y - 1);
367                 visit(x, y -
1);
368                 visit(x +
1, y - 1);
369
370                 visit(x -
1, y);
371                 visit(x +
1, y);
372
373                 visit(x -
1, y + 1);
374                 visit(x, y +
1);
375                 visit(x +
1, y + 1);
376             }
377         }
378     }
379 }


Gõ tìm kiếm nhanh...